#include <jni.h>
#include <string>
#include <opencv2/opencv.hpp>
#include <android/native_window_jni.h>
#include <pthread.h>
using namespace cv;

ANativeWindow *window = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化 锁


DetectionBasedTracker *tracker = 0;
class CascadeDetectorAdapter:public DetectionBasedTracker::IDetector{
public:
    CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector): IDetector(),Detector(detector){

    }

    void detect(const cv::Mat &image, std::vector<cv::Rect> &objects){
      Detector->detectMultiScale(image, objects, scaleFactor, minNeighbours, 0, minObjSize,
                                 maxObjSize);
    }

private:
    CascadeDetectorAdapter();
    cv::Ptr<cv::CascadeClassifier> Detector;
};

extern "C"
JNIEXPORT void JNICALL
Java_com_luisliuyi_demo_opencv_MainActivity_init(JNIEnv *env, jobject thiz, jstring model_) {
  const char *model = env->GetStringUTFChars(model_, 0);

  if (tracker) {
    tracker->stop();
    delete tracker;
    tracker = 0;
  }

  //创建一个检测器
  Ptr<CascadeClassifier> classifier = makePtr<CascadeClassifier>(model);
  Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(classifier);

  //创建一个跟踪器
  Ptr<CascadeClassifier> classifier1 = makePtr<CascadeClassifier>(model);
  Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(classifier1);

  DetectionBasedTracker::Parameters detectorParams;
  tracker = new DetectionBasedTracker(mainDetector, trackingDetector, detectorParams);

  //开启跟踪器
  tracker->run();

  env->ReleaseStringUTFChars(model_, model);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_luisliuyi_demo_opencv_MainActivity_setSurface(JNIEnv *env, jobject thiz, jobject surface) {
    pthread_mutex_lock(&mutex);
    // 先释放之前的显示窗口
    if (window) {
        ANativeWindow_release(window);
        window = nullptr;
    }
    // 创建新的窗口用于视频显示
    window = ANativeWindow_fromSurface(env, surface);
    pthread_mutex_unlock(&mutex);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_luisliuyi_demo_opencv_MainActivity_release(JNIEnv *env, jobject thiz) {
    if (tracker) {
        tracker->stop();
        delete tracker;
        tracker = 0;
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_luisliuyi_demo_opencv_MainActivity_postData(JNIEnv *env, jobject thiz, jbyteArray data_,
                                                     jint w, jint h, jint camera_id) {
  // nv21
  jbyte *data = env->GetByteArrayElements(data_, NULL);

  Mat src(h + h / 2, w, CV_8UC1, data);

  //nv21->RGBA
  cvtColor(src, src, COLOR_YUV2RGBA_NV21);

  if (camera_id == 1) {
    //逆时针旋转90度
    rotate(src, src, ROTATE_90_COUNTERCLOCKWISE);
    //水平翻转 镜像
    flip(src, src, 1);
  } else {
    //顺时针旋转90度
    rotate(src, src, ROTATE_90_CLOCKWISE);
  }

  //灰色
  Mat gray;
  cvtColor(src, gray, COLOR_RGBA2GRAY);

  //增强对比度 (直方图均衡)
  equalizeHist(gray, gray);

  //定位人脸 N个
  std::vector<Rect> faces;
  tracker->process(gray);
  tracker->getObjects(faces);

  for (Rect face : faces) {
    //画矩形
    rectangle(src, face, Scalar(255, 0, 255));
  }

  //显示
  pthread_mutex_lock(&mutex);
  if (!window) {
    pthread_mutex_unlock(&mutex); // 出现了问题后，必须考虑到，释放锁，怕出现死锁问题
  }

  ANativeWindow_setBuffersGeometry(window, src.cols, src.rows, WINDOW_FORMAT_RGBA_8888);
  ANativeWindow_Buffer window_buffer;

  if (ANativeWindow_lock(window, &window_buffer, 0)) {
    ANativeWindow_release(window);
    window = 0;
    pthread_mutex_unlock(&mutex);
    return;
  }

  uint8_t *dst_data = static_cast<uint8_t *>(window_buffer.bits);
  int dst_linesize = window_buffer.stride * 4;
  uint8_t *src_data = src.data;
  int src_lineSize = src.cols * 4;
  for (int i = 0; i < window_buffer.height; ++i) {
    memcpy(dst_data + i * dst_linesize, src_data + i * src_lineSize, dst_linesize);
  }
  // 数据刷新
  ANativeWindow_unlockAndPost(window);

  pthread_mutex_unlock(&mutex);

  //释放
  src.release();
  gray.release();
  env->ReleaseByteArrayElements(data_, data, 0);
}